<?php

// phpinfo(); return true;

/**
 * 另一种告诉 内置服务器 这个请求 是由 php 处理 还是由 内置服务器 处理 的办法
 * 使用起来太过灵活，不好控制，引入这个变量就需要引入对这个变量的判断逻辑，
 * 这个变量的设置时机没啥要求，很自由，这是灵活之处，
 * 但同样的，对这个变量的判断逻辑 也就不好控制时机，这是麻烦之处。
 * 设置时没啥要求 但 判断时需要在 echo 前进行判断，
 * 如果 这个请求应该由 内置服务器 处理($_is_php_serve == false，最好还要加上验证 GET 请求, cli-server, 请求的是资源文件)，
 * 那么就应该停止，然后返回 false 给 php, 告诉 内置服务器 这个请求 由 内置服务器 处理
 * 如果 这个请求应该由 php 处理，那么就可以继续执行剩余的逻辑，完成后最后返回 true 给 php, 告诉 内置服务器 这个请求 由 php 处理。
 */
// $_is_php_serve = true;


/**
 * 把变量限制在局部
 *
 * return bool - is php serve this request - 这个返回值(return_value)将被透传式返回给 php
 * !!! 注意，不要把这个 return_value 理解成了 进程退出码(exit_code),
 * 设计这个脚本是给服务器进程使用的，服务器进程属于常驻进程，exit_code 没多大意义，
 * 如果 整个服务器进程 都退出了，服务不就跪了吗，
 * 如果 只是 某个 worker 进程 意外退出 或者 按计划退出 那么 master 进程也会根据情况 增加 或者 减少 worker 进程，exit_code 也没多大意义
 *
 * 当 php 作为 cgi 程序 或者 类似的程序 位于一个 web server 后面时，return_value 没多大意义，固定为默认值 true 就可以了。
 * 因为 web server 可以配置如何处理请求，当一个请求走到这里来时就意味着 web server 将这个请求交给了 php 处理，
 * php 要做的就是将处理结果返回给 web server。如果 php 处理不了这个请求，那么就应该返回 400, 404, 500 等
 * 非 200 类型的结果给 web server, 这也是一种处理, 也是 php 处理了这个请求。
 * 所以在这种场景下就不会发生 php 不返回处理结果给 web server, 而是告诉 web server 这个请求我处理不了，应该由你处理。
 *
 * 但是当 php 作为 cli-server 程序时，由于无法单独配置如何处理请求，那么我们写的 php 程序需要告诉 内置服务器
 * 这个请求 是由 php 处理 还是由 内置服务器 处理，在这种场景下 这个 return_value 就可以派上用场了。
 * 当确定了这个请求应该由 内置服务器 处理 且 php 是 cli-server 且 请求的是资源文件 时，
 * return false 并将被透传式返回给 php，告诉 内置服务器 这个请求 由 内置服务器 处理，
 * return true 并将被透传式返回给 php，告诉 内置服务器 这个请求 由 php 处理。
 *
 * https://www.php.net/manual/en/features.commandline.webserver.php
 *
 * URI requests are served from the current working directory where PHP was started,
 * unless the -t option is used to specify an explicit document root.
 * If a URI request does not **SPECIFY A FILE**, then either index.php or index.html in the given directory are returned.
 * If neither file exists, the lookup for index.php and index.html will be continued in the parent directory
 * and so on until one is found or the document root has been reached.
 * If an index.php or index.html is found, it is returned and $_SERVER['PATH_INFO'] is set to the trailing part of the URI.
 * Otherwise a 404 response code is returned.
 *
 * If a PHP file is given on the command line when the web server is started it is treated as a "router" script.
 * The script is run at the start of each HTTP request.
 * IF THIS SCRIPT RETURNS **FALSE**, then the requested resource is returned as-is.
 * Otherwise the script's output is returned to the browser.
 *
 * @return bool
 */
function _main_route()
{
    define('BASE_DIR', realpath(__DIR__ . '/..'));

    /** @var \Composer\Autoload\ClassLoader $loader */
    $loader = require BASE_DIR . '/vendor/autoload.php';
    $loader->addPsr4('PhpYes\\', BASE_DIR);

    $app = null; // todo new App();
    \PhpYes\Yes::$p = $app;

    \PhpYes\Modules\Log\LoggerManager::init($app->config('log.php'));

    try {
        // \Project\Com\Session::init(); // 后面整合进 App

        $router = $app->router();
        $router->route(\PhpYes\Yes::$p->getRequest()->getMethod(), \PhpYes\Yes::$p->getRequest()->getPath());
        $cls = $router->cls;
        $func = $router->func;
        if ($cls && $func) {
            $obj = new $cls();
            if (method_exists($obj, 'preflight')) {
                $obj->preflight($app);
            }
            $obj->$func($app);
        } else {
            throw new \PhpYes\Com\Http404Exception();
        }
    } catch (\Exception $e) {
        // 这里要根据实际情况来渲染
        if ($e instanceof \PhpYes\Com\HttpException) {
            // 这种异常体系(即HttpException以及它的子类)下的异常我们认为是可以展示给用户看的
            \PhpYes\Modules\Log\Example\AppLogHelper::logException($e);

            while ($e->getHttpRspCode() == 404 && php_sapi_name() == 'cli-server') {
                if (in_array($router->http_method, ['POST', 'PUT', 'DELETE', 'PATCH'])) {
                    break;
                }

                $extname = $app->lower_extname();
                if (empty($extname)) {
                    break;
                }

                $ext_type_map = \PhpYes\Com\ExtName::ext_type_map();
                if (isset($ext_type_map[$extname])) {
                    return false;
                }

                break;
            }

            if (\PhpYes\Yes::$p->getRequest()->isXMLHttpRequest()) {
                $app->render()->returnJsonWithErrorMessage($e->getMessage(), $e->getHttpRspCode());
            } else {
                // http_response_code($e->getHttpRspCode());
                // echo $e->getMessage();
                $app->render()->displayError($e->getMessage(), $e->getHttpRspCode());
            }
        } else {
            // 这种不知道类型的异常不能展示给用户，以防异常中有敏感数据
            \PhpYes\Modules\Log\Example\AppLogHelper::logException($e);
            $env = $app->env();
            if ($env == \PhpYes\Apps\BaseApp::ENV_PRODUCTION) {
                // http_response_code(500);
                // echo '服务器错误，请稍后重试!';
                $errMsg = '服务器错误，请稍后重试!';
                if (\PhpYes\Yes::$p->getRequest()->isXMLHttpRequest()) {
                    $app->render()->returnJsonWithErrorMessage($errMsg, 500);
                } else {
                    $app->render()->display5xx($errMsg, 500);
                }
            } else { // 非生产环境的话，那么一般就是开发或者测试环境了，这种情况下直接抛出异常以便渲染出来给开发或者测试人员查看，以便定位问题
                throw $e;
            }
        }
    }

    return true;
}

return _main_route();
